/*
 * @Author: szx
 * @Date: 2023-03-29 14:30:22
 * @LastEditTime: 2023-03-29 20:10:10
 * @Description: 
 * @FilePath: \learn\fullstackopen\part3\index.js
 */
require('dotenv').config()

const express = require('express')
const app = express()
const morgan = require('morgan')
const cors = require('cors')
const Person = require('./models/person')
app.use(express.static('build'))

app.use(cors())

morgan.token('content', (request) =>
    request.method === 'POST' && request.body.name
        ? JSON.stringify(request.body)
        : null
)
app.use(express.json())
app.use(morgan(':method :url :status :res[content-length] - :response-time ms :content'))

app.post('/api/persons', (request, response, next) => {
    const body = request.body
    if (!body.name || !body.number) {
        return response.status(400).json({
            error: 'name or number missing'
        })
    }

    const person = new Person({
        name: body.name,
        number: body.number,
        date: new Date(),
    })

    person.save().then(savePerson => {
        response.json(savePerson)
    }).catch(error => next(error))
})

app.get('/api/persons', (request, response) => {
    Person.find({}).then(result => {
        response.json(result)
    }).catch(error => {
        console.log(error)
        response.status(500).end()
    })
})

app.get('/info', (request, response) => {
    Person.find({}).then(result => {
        response.send(
            `<div>
                <p>Phonebook has info for ${result.length} people</p>
            </div>
            <div>
                <p>${new Date()}</p>
            </div>`)
    }).catch(error => {
        console.log(error)
        response.status(500).end()
    })

})

app.get('/api/persons/:id', (request, response, next) => {
    Person.findById(request.params.id).then(result => {
        if (result) {
            response.json(result)
        } else {
            response.status(404).end()
        }
    }).catch(error => next(error))
})

app.delete('/api/persons/:id', (request, response, next) => {
    Person.findByIdAndDelete(request.params.id).then(result => {
        response.status(204).end()
    }).catch(error => next(error))
})

app.put('/api/persons/:id', (request, response, next) => {
    const body = request.body

    const person = {
        name: body.name,
        number: body.number
    }
    Person.findByIdAndUpdate(request.params.id, person,
        { new: true, runValidators: true, context: 'query' })
        .then(updatePerson => {
            response.json(updatePerson)
        }).catch(error => next(error))
})

const unknownEndpoint = (request, response) => {
    response.status(404).send({ error: 'unknown endpoint' })
}
app.use(unknownEndpoint)


// 错误处理程序
const errorHandler = (error, request, response, next) => {
    console.error(error.message)
    if (error.name === 'CastError') {
        return response.status(400).send({ error: 'malformatted id' })
    } else if (error.name === 'ValidationError') {
        console.log('ValidationError')
        return response.status(400).json({ error: error.message })
    }
    next(error)
}

app.use(errorHandler)

const PORT = process.env.PORT
app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`)
})